Boilerplate 1. Semester

Linked List

public class Shop {
    public static void main(String[] args) {
        ShoppingList list = new ShoppingList();

        ShoppingListItem brot = new ShoppingListItem("Brot", 4.5, TaxClass.REDUCED);
        ShoppingListItem duschgel = new ShoppingListItem("Duschgel", 1.99, TaxClass.FULL);
        ShoppingListItem marmelade = new ShoppingListItem("Marmelade", 1.32, TaxClass.REDUCED);
        ShoppingListItem kaese = new ShoppingListItem("Käse", 0.99, TaxClass.REDUCED);

        list.put(brot);
        list.put(duschgel);
        list.put(marmelade);
        list.put(kaese);

        System.out.println("Folgendes ist in der Liste: \n");
        System.out.println(list.toString());

        System.out.println("\nTeste ob Elemente in der Liste sind ...");
        System.out.println("Duschgel in der Liste: " + list.isInList(duschgel));

        System.out.println("\nHole Elemente aus der Liste: ");
        System.out.println(list.get("Brot"));
        System.out.println(list.get("Nicht in der Liste") + " (sollte sein: null)");

        System.out.println("Entferne 'Käse'...");
        list.remove("Käse");
        System.out.println(list.toString());
    }
}
public class ShoppingList {

    private ShoppingListLinkItem head;

    public void put(ShoppingListItem item) {
        head = new ShoppingListLinkItem(item, head);
    }

    public ShoppingListItem get(String name) {
        ShoppingListLinkItem tempHead = head;

        while (!tempHead.data.getName().equals(name)) {
            tempHead = tempHead.next;
            if (tempHead == null)
                return null;
        }
        return tempHead.data;
    }

    public void remove(String name) {
        // Item at the start
        if (head == null ) {
            return;
        } else if (head.data.getName().equals(name)) {
            head = head.next;
        }

        // Item at the mid or end
        ShoppingListLinkItem tempHead = head;
        while (true) {
            if (tempHead.next == null) {
                return; // end from the list (next item null) -> item not found
            } else if (tempHead.next.data.getName().equals(name)) {
                tempHead.next = tempHead.next.next; // Overwrite pointer from the removable item
                return;
            }
            tempHead = tempHead.next;
        }
    }

    public boolean isInList(ShoppingListItem item) {
        ShoppingListLinkItem tempHead = head;

        while (!tempHead.data.equals(item)) {
            tempHead = tempHead.next;
            if (tempHead == null)
                return false;
        }
        return true;
    }

    public String toString() {
        StringBuilder str = new StringBuilder("{");
        ShoppingListLinkItem tempHead = head;

        while (tempHead != null) {
            str.append(tempHead.data.toString() + ", ");
            tempHead = tempHead.next;
        }

        return str.substring(0, str.length()-2) + "}";
    }
}
public class ShoppingListLinkItem {

    ShoppingListItem data;
    ShoppingListLinkItem next;

    public ShoppingListLinkItem(ShoppingListItem data, ShoppingListLinkItem next) {
        this.data = data;
        this.next = next;
    }

}

Rekursiv

public static int binarySearchRec(int[] arr, int value) {
    return binarySearchRec(arr, value, 0, arr.length - 1);
}

private static int binarySearchRec(int[] arr, int value, int left, int right) {
    if (left > right) {
        return -1;
    }

    int middle = (left + right) / 2;

    if (arr[middle] < value) {
        return binarySearchRec(arr, value, middle + 1, right);
    } else if (arr[middle] > value) {
        return binarySearchRec(arr, value, left, middle - 1);
    } else {
        return middle;
    }
}
public static int countUnevenRec(int[] a) {
    return countUnevenRec(a, 0);
}

private static int countUnevenRec(int[] a, int i) {
    if (i >= a.length)
        return 0;
    return a[i] % 2 + countUnevenRec(a, i+1);
}
public static int ggT(int x, int y) {
    if (x == y) {
        return x;
    } else if (x > y) {
        return ggT(x - y, x);
    }
    return ggT(x, y - x);
}
public static long powRecursive(long x, long n) { 
    if (n == 0) {
        return 1;
    } else if ((n/2)*2 == n) {
        long a = powRecursive(x, n/2);
        return a * a;
    }
    return x * powRecursive(x, n-1);
}
public static long isFactorialRec(long i) {
    if (i == 1) {
        return 1;
    }
    return isFactorialRec(i, 2);
}

public static long isFactorialRec(long i, long div) {
    long quota = i/div;

    // termination conditions
    if (quota * div != i) { // when it isn't a factorial
        return -1;
    } else if (quota == 1) { // when it is a factorial
        return div;
    }

    // next call
    return isFactorialRec(quota, div+1);
}
public static long factorialRecursive(long n) {
    if (n == 0) return 1;
    return (n > MAX_N) ? Long.MIN_VALUE : n * factorialRecursive(n-1);
}

public static void main(String[] args) {
    for (int i = 0; i < 235; i++) {
        System.out.println(i + ": " +factorialFor(i));
    }

}

Enums

public enum TrafficLightColor {
    RED(10) {
        public int getBrightness(){ 
            return 10;
        }
    },
    RED_YELLOW(8), GREEN(5), YELLOW(10);

    private int brightness;

    private TrafficLightColor(int brightness) {
        this.brightness = brightness;
    }

    public int getBrightness() {
        return brightness;
    }

    public void setBrightness(int brightness) {
        this.brightness = brightness;
    }
}
public class TrafficLight {

    private TrafficLightColor currentColor;

    public void reset() {
        currentColor = TrafficLightColor.RED;
    }

    public TrafficLightColor getCurrentColor() {
        return currentColor;
    }

    public TrafficLightColor[] getAllColors() {
        return TrafficLightColor.values();
    }

    public void setCurrentColor(TrafficLightColor color) {
        this.currentColor = color;
    }

    public void doSwitch() {
        switch (currentColor) {
        case RED:
            currentColor = TrafficLightColor.RED_YELLOW;
            break;
        case RED_YELLOW:
            currentColor = TrafficLightColor.GREEN;
            break;
        case GREEN:
            currentColor = TrafficLightColor.YELLOW;
            break;
        case YELLOW:
            currentColor = TrafficLightColor.RED;
            break;
        }
    }

    public static void main (String[] args) {
        System.out
                .println("\nget one special value from string representation:");
        TrafficLightColor single = TrafficLightColor.valueOf("RED");
        System.out.println(single);

        // Which position in the enum
        System.out.println("Ordinal of GREEN:" + TrafficLightColor.GREEN.ordinal());

        System.out.println("\nbrightness of RED: "
                + TrafficLightColor.RED.getBrightness());
        TrafficLightColor.RED.setBrightness(6);
        System.out.println("\nbrightness of RED: "
                + TrafficLightColor.RED.getBrightness()); //Still 10
    }
}

Seiteneffekte

/**
 * Half from a set to b and c
 * a = 4 b = 3 c = 10 d = true f1 = 2.0
 * @return b ()
 */
public int expressionA() {
    return b = c = (a / 2);
}

/**
 * Set a to 10 and multiply the value of a with 4
 * @return b
 */
public int expressionB() {
    return b = c = (a = 10) << 2;
}

/**
 * Controls if a and c is divideable by 2
 * @return boolean
 */
public boolean expressionC() {
    return (a % 2 == 0) && (c % 2 == 0);
}

/**
 * 
 * @return boolean
 */
public boolean expressionD() {
    //return d & (f1) > 10 & (a = (int) f1) == a;
    return d & (a = (int) f1) > 10;
}

public boolean expressionE() {
    //return (b & 0b100) >> 2 == 1 && (b & 0b10) >> 1 == 1;
    return (b&3<<1)==3<<1;
}

public void expressionF() {
    f1 = ((a % 10 == 0) && (b % 10 == 0)) ? a / 3.0f : 10 * a;
}

Interfaces

image.png

package container2;

/**
 * Specification of a simple stack
 */
public interface Stack {
    void push(Object obj);
    Object pop();
    Object top();
    boolean empty();
}
package container2;

/**
 * A simple stack implementation backed by an array of fixed size, which can
 * hold objects. Among other things an adequate error handling is missing
 */
public class StackArrayImpl implements Stack {
    [ ... ]

    public StackArrayImpl(int cap) { ... }

    public void push(Object obj) { ... }
    public Object pop() { ... }
    public Object top() { ... }
    public boolean empty() { ... }

    public String toString() { ... }
}
package container2;

/** A simple stack implementation backed by a linked list of
  * objects.
  * Among other things an adequate error handling is missing
  */
public class StackLinkedListImpl implements Stack { 
    [...]

    public void push(Object c) { ... }   
    public Object pop() { ... }
    public Object top() { ... }
    public boolean empty() { ... }
    public String toString()  { ... }      
}

class ListLinkElement  { ... }

Verhaltenspakete

Interface "erzwingen" einen gemeinsammen Verhaltensaskept (gleiche Methoden) verschiedener Klassen -> notwendig um Callback zu realisieren

Interface:

public interface Callback {
    void callback();
}

Implementierung des Interface:

public class CallbackImpl implements Callback{
    @Override
    public void callback() {
        System.out.println("I am the callback");
    }
}

Ausführung des Interfaces:

public class Main {
    public static void main(String[] args) {
        CallbackImpl myCallback = new CallbackImpl();
        methodThatExpectsACallback(myCallback);

        // Alternativ mit Lambda, da nur eine Methode im Interface
        methodThatExpectsACallback(() -> System.out.println("I am the callback from the Lambda"));
    }
    private static void methodThatExpectsACallback(Callback callback){
        System.out.println("I am the method.");
        callback.callback();
    }
}

API-Interfaces von java.lang

Cloneable

Interface hat keine Methode -> dient zur Markierung, dass ein Objekt geklont werden darf.
Die protected clone() Methode kann zu einer plublic Methode überschrieben werden.

public MyClass clone() throws CloneNotSupportedException {
    MyClass newClass = (MyClass) super.clone();
    // TODO: clone of reference variables
    // clone of immutable object not necessary
    return s;
}

Complarable

Klassen erhalten dadurch eine Ordnung, die durch einen Integer repräsentiert wird

Zu implementierende Methode:

public int compareTo(Object o) // with significant return values <0, 0, >0;

Exceptions

try {
    // Code here can throw exception
} catch (SomeException e) {
    // handle SomeException
} catch (FooException | BaaException e) {
    // handle FooException or BaaException
} finally {
    // cleen up
    // code here will be always executed
}

Werfen von Exceptions

throw new SomeException("Exception here");

Eigene Exceptions

public class MyException extends Exception {
    public MyException () { super(); }
    public MyException (String s) { super(s); }

}
  • java.lang.Error: Verwendung für Fehler in der Laufzeitumgebung
  • java.lang.Exception: checked exception -> müssen gecatched werden
    • Verwendung für voraussichtliche Probleme, die während der normalen Programmausführung auftreten können
  • java.lang.RuntimeException: unchecked exception -> können gecatched werden
    • Verwendung für fehlerhafte Programmierung oder ...
    • Benutzerdefinierte Exceptions

Geschachtetlte Klassen

Innere Klasse

wenn Klasse in mehreren Methoden verwendet wird

modifier class A {
    // Attributes Class A
    // [...]

    modifier class B {
        // Attributes Class B
        // [...]
    }
}

Statische innere Klasse

wenn kein Zugriff auf Objektattribute nötig

modifier class A {
    // Attributes Class A
    // [...]

    static modifier class B {
        // Attributes Class B
        // [...]
    }
}

Anonyme Klasse

Wenn nur einmal im Code verwendet

modifier class A {
    // Attributes Class A
    // [...]

    BaseClass anonymous = new BaseClass() {
        // variables and methods of anonymous class
        // ...
    }
}

Lokale Klasse

Wenn mehrfach in einer Methode

modifier class A {
    // Attributes Class A
    // [...]

    modifier method(...) {
        static modifier class B {
            // Attributes Class B
            // [...]
        }
    }
}

Die Klassen java.util.Enumeration und java.util.Interator

Enumeration:
Generates a series of elements, one at a time. Successive calls to the nextElement() method return successive elements of the series.

public interface Enumeration<E> {

    boolean hasMoreElements();

    E nextElement(); // returns next element and points to it

    default Iterator<E> asIterator() {
        return new Iterator<>() {
            @Override public boolean hasNext() {
                return hasMoreElements();
            }
            @Override public E next() {
                return nextElement();
            }
        };
    }
}

Iterator:
Takes the place of Enumeration in the Java Collections Framework.
Differ from enumerations in two ways:

  • Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics.
  • Method names have been improved.
public interface Iterator<E> {

    boolean hasNext();

    E next();

    /**
     * Removes from the underlying collection the last element returned
     * by this iterator (optional operation).
     * 
     * This method can be called only once per call to next.
     *
     * @throws UnsupportedOperationException if the `remove`
     *         operation is not supported (implemented) by this iterator
     *
     * @throws IllegalStateException if the `next` method has not
     *         yet been called, or the `remove` method has already
     *         been called after the last call to the `next` method
     */
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

    // [...]
}

Example:
To print all elements of a Vector<E> v:

for (Enumeration<E> e = v.elements(); e.hasMoreElements();)
    System.out.println(e.nextElement());

Unittests

JUnit gehör nicht zum JDK und muss seperat im CLASSPATH zur Verfügung stehen

class ClassTest {
    // classvariables here will be persistent

    @BeforeAll
    static void setupBeforeAll() throws Exception{
    }

    @AfterAll
    static void tearDownBeforeAll() throws Exception{
    }

    @BeforeEach
    void setup() throws Exception {
    }

    @AfterEach
    void tearDown() throws Exception {
    }

    @Test
    public void testSomething() {
        // here one of your tests
    }
}

Assert-Statements

@Test
void demonstrateAssert() {
    int i = 5;
    int j = 6;
    assertEquals(i, j, "a message");
}

Test-Suiten - Zusammenfassen mehrerer Unit-Tests

@Suite
@SelectClasses({
    SomeTestClassA.class,
    SomeTestClassB.class
})
public class ATestSuite {
}

Mocking

creating objects that simulate the behaviour of real objects

Mock-Objekt dient als Dummy-Objekt anstelle eines realen Objekts, welches bislang nicht zum Testen zur Verfügung steht oder schlecht dafür geeignet ist.

Metaprogramming

Geschriebene Programme, die andere Programme repräsentieren oder manipulieren

Verwendung in der Praxis:

  • Generative Programmierung (Bsp.: Codegenerierung mit Schablonen)
  • Reflection (Programm untersucht sich selber)
  • ...

Introspection und Reflection

Introspection: Klassen können (im Plugin) zur Laufzeit angeschaut werden

  • Informationen über elementare Datentypen, Arrays und Klassen zur Laufzeit
  • JVM Informationen von Class-Files als Meta-Objekt zur Verfügung Reflection: Neue Klassen können zur Laufzeit geladen und instanziiert werden
  • Meta-Objekte von der JVM können verändert werden

Einsatzgebiete:

  • Plugins
  • Frameworks
  • Serialisierung
  • ...

Die zentrale Klasse java.lang.Class

kann durch Aufruf von getClass() einer Klasse erhalten werden
oder duch Konstante <package.to.Classname>.class (wenn die Klasse zur Kompilezeit vorliegt)

Wichtigste Methoden:

Weitere Metaklassen in java.lang.reflect

  • Method: stellt eine Methode innerhalb einer Klasse dar
  • Field: z.B. für Variablen -> auslesen und setzen von Werten
  • Constructor: erlabut Erzeugen von neuen Instanzen der beobachteten Klasse
  • Modifier: condiert als int-Wert (bietet methode zom decodieren)
  • Array: enthält statische Methoden zum dynamischen Kreieren und Manipulieren von Arrays

Dynamisches Laden von Klassen

Class<?> clazz = Class.forName("MyClass");
Constructor<?> constructor = clazz.getDeclaredConstructor(new Class[] {/*Parameters type(s)*/});
MyClass myClass = (MyClass) constructor.newInstance(new Object[] {/*Parameters value(s)*/});
myClass.myPublicMethod(); // e.g. call a public method

// private methoden aufrufen
Method privMethod = clazz.getDeclaredMethod("myPrivateMethod", new Class[] {});
privMethod.setAccessible(true);
privMethod.invoke(myClass); // invoke this private method from myClass object

Annotationen

Geben zusätzliche Informationen, welche nicht der eigentlichen Logik des Progammes sind

Vordefinierte Annotationen

Dient zur Steuerung des Compilers, um den Entwickler auf bestimmte Tatsachen hinzuweisen

Beispiele dafür sind:

  • @Deprecated
  • @Override
  • @SuppressWarnings

Selbstdefinierte Annotationen

Erlaubt es den Code mit Eigenschaften zu beschreiben
-> Wichtig zum Beispiel im Kotext der Reflection, bzw. Frameworks

Benutzung und Definierung einer eigenen Annotation:

// simple annotation
public @interface MyMarker {}
// usage:
@MyMarker
public void myMethod1() { ... }
// with named attributes
public @interface ToDo {
    String what();
    int count() default 1;
}
// usage:
@ToDo (what="execute", count=3)
public myMethod2() { ... }
public @interface Name {
    String first();
    String last();
}
// complex annotation
public @interface Reviewer {
    Name value();
}
// usage:
@Reviewer(@Name(first="Joe", last="Doe"))
public void myMethod3() { ... }

Beispiel mit Reflection:

...
Method[] methods = clazz.getMethods();
for (method : methods) {
    ToDo toDo = method.getAnnotation(ToDo.class);
    if (toDo != null) {
        for (int i = 0; i < toDo.count(); i++)
            method.invoke(myClass);
    }
}

Junit-Framework aggiert nach dem selben Prinzip

Generics

public class SingleObjectHolder<E> {
    private E element;

    public void put(E element) {
        this.element = element;
    }

    public E get() {
        return element;
    }
}

Verwendung:

SingleObjectHolder<String> strHolder = new SingleObjectHolder<>();
strHolder.put("Hello");
String s = strHolder.get();

SingleObjectHolder<char[]> charArrHolder = new SingleObjectHolder<>();
charArrHolder.put(new char[]{'a', 'b', 'c'});
char c = charArrHolder.get()[0];

Generics bei Methoden

// hier Generic nicht unbeding notwendig, da folgendes auch mit 
// upcast zu Object möglich ist
public static <T> void swap(T[] a, int i, int j) {
    T t = a[i];
    a[i] = a[j];
    a[j] = t;
}

public static <T> T getLast(T[] a) {
    return a[a.lenght-1];
}

Verwendung:

int[] ia = {1, 2, 3, 4};
// Implicit
swap(ia, 0, 1);
String s = getLast(ia);

// Explicit
ClassName.<Integer>swap(ia, 0, 1);
s = ClassName.<String>getLast(ia);

Grenzen

  • Generics können keine primitive Datentypen sein
  • keine statischen Variablen mit Generic-Typ
  • Generic kann nicht mit instanceof verwendet werden
  • Generic kann nicht im Zusammenhang mit new verwendet werden

Beispiele:

// Geht nicht!!!
public static <T> T makeInstance() {
    return new T();
}

// Ausweg
public static <T> T makeInstance(Class<T> clazz) {
    return clazz.newInstance();
}
// Aufruf
makeInstance(MyClass.class);
// Geht nicht!!!
public static <T> T[] resize(T[] a) {
    T[] cl new T[a.length + 1];
    return cl;
}

// Ausweg
public static <T> T[] resize(T[] a, Class<T> elementType) {
    T[] cl = (T[]) Array.newInstance(elementType, a.length + 1);
    return cl;
}
// Aufruf
makeInstance(myClassArr, MyClass.class);

Mit Vererbung

// Parent class
class A<T> { }

class B<T> extends A { } // allowed not recomendet
class B<T> extends A<T> { } // better, B and A have same generic

class B extends A<T> { } // not allowed
class B extends A<String> { } // allowed
class B<T> extends A<String> { } // also allowed

Vorsicht:
Kein Typcast möglich

A<String> a1 = new A<>();
A<Integer> a2 = new A<>();

a1 = (A<String>) a2; // not allowed

Wildcards

Unbounded

A<Integer> intA = new A<>();

A rawA = intA; // warning: should be parameterized
intA = rawA; // warning: type safety

A<?> unboundedA = intA; // no warning
intA = unboundedA; // error: type mismatch

Upperbounded

class A<T extends Number>

-> Typparameter kann nur Number oder unterhalb von Number (Double, Interger, etc.) sein

Mit Interfaces:

class A<T extends MyClass & MyInterface1 & MyInterface2 & MyInterface3>

Lowerbounded

Schränken Parameter-Typ ein

static void doIt(B<? super Integer> b)

-> Erlaubt Supertypes und sich selbst (Integer, Number, Object)

Mit Reflection

Die Klasse Class selbst ist parametrisierbar (Class<T>)

Class<String> strClass;
Class<?> unboundClass;

/// returns the exact paramised type
strClass = String.class;
unboundClass = String.class; // Also allowed

/// returns only with wildcard paramised type
strClass = (Class<String>) "abc".getClass(); // warning: Type safety
unboundClass = "abc".getClass();

// Needs to be checked with ClassNotFoundException
strClass = (Class<String>) Class.forName("java.lang.String"); // warning: Type safety
unboundClass = Class.forName("java.lang.String");

Java Collections Framework

image.png

Collections Interface

Method Description
add(Object) This method is used to add an object to the collection.
addAll(Collection c) This method adds all the elements in the given collection to this collection.
clear() This method removes all of the elements from this collection.
contains(Object o) This method returns true if the collection contains the specified element.
containsAll(Collection c) This method returns true if the collection contains all of the elements in the given collection.
equals(Object o) This method compares the specified object with this collection for equality.
hashCode() This method is used to return the hash code value for this collection.
isEmpty() This method returns true if this collection contains no elements.
iterator() This method returns an iterator over the elements in this collection.
parallelStream() This method returns a parallel Stream with this collection as its source.
remove(Object o) This method is used to remove the given object from the collection. If there are duplicate values, then this method removes the first occurrence of the object.
removeAll(Collection c) This method is used to remove all the objects mentioned in the given collection from the collection.
removeIf(Predicate filter) This method is used to remove all the elements of this collection that satisfy the given predicate.
retainAll(Collection c) This method is used to retain only the elements in this collection that are contained in the specified collection.
size() This method is used to return the number of elements in the collection.
spliterator() This method is used to create a Spliterator over the elements in this collection.
stream() This method is used to return a sequential Stream with this collection as its source.
toArray() This method is used to return an array containing all of the elements in this collection.
Interfaces that Extend the Java Collections Interface

-> das Collection interface implementiert Iterator interface

Map Interface

repräsentiert durch Schlüssel-Wert-Paare

Iterieren über den Inhalt einer Map:

for (Map.Entry<String, Integer> entry : map.entrySet()) {
    ...
}

Allgemeine Collection-Implementierungen im JDK

Implementierung von:

  • List
    • ArrayList
    • Vector (thread-safe)
    • LinkedList
  • Queue und Deque
    • LinkedList
    • ArrayDeque
    • PriorityQueue
  • Set
    • HashSet
    • LinkedHashSet
    • EnumSet
  • SortedSet
    • TreeSet
  • Map
    • Hashtable (thread-safe)
    • HashMap
    • WeakHashMap
    • IdentityHashMap
  • SortedMap
    • TreeSet

Lambdas

Interne Iteration

Rahmen:

class IntArrayUtils {
    public static void forEach(int[] array, IntConsumer consumer) {
        for (int value : array) {
            consumer.accept(value);
        }
    }
}

Dazugehöriges Interface:

interface IntConsumer {
    void accept(int value);
}

Benutzung:
-> Mit anonymen Klassen:

int[] array = {1, 2, 3};
IntArrayUtils.forEach(array, new IntConsumer(){
                    @Override
                    public void accept(int value) {
                        System.out.println(value);
                    }
                });

IntArrayUtils.forEach(array, new IntConsumer(){
                    @Override
                    public void accept(int value) {
                        if (value%2 == 0)
                            System.out.println(value);
                    }
                });

-> Mit Lambdas:

int[] array = {1, 2, 3};
IntArrayUtils.forEach(array, i -> System.out.println(i));

IntConsumer printIfOdd = i -> {
    if (value%2 == 0)
        System.out.println(value);
}
IntArrayUtils.forEach(array, printIfOdd);